package com.ssd.handler.impl;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;

import com.ssd.api.payment.dto.enums.RefundStatusEnum;
import com.ssd.api.payment.dto.enums.TradingStateEnum;
import com.ssd.exception.LogicException;
import com.ssd.enums.TradingEnum;
import com.ssd.handler.BeforePayHandler;
import com.ssd.model.domain.RefundRecord;
import com.ssd.model.domain.Trading;
import com.ssd.service.RefundRecordService;
import com.ssd.service.TradingService;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.List;

/**
 * 交易前置处理接口实现类
 *
 * @author cy
 * @version 1.0
 */
@Component
public class BeforePayHandlerImpl implements BeforePayHandler {
    //交易订单表服务
    @Resource
    private TradingService tradingService;
    /**
     * 使用Resource注解注入IdentifierGenerator实例
     * IdentifierGenerator用于生成唯一标识符，是系统中的一个关键服务
     * 通过依赖注入，可以在需要的地方直接使用，无需手动创建实例
     */
    @Resource
    private IdentifierGenerator identifierGenerator;
    //退款记录表服务类
    @Resource
    private RefundRecordService refundRecordService;

    /**
     * 校验创建交易单的参数，通过则生成交易号
     * @param tradingEntity 交易实体
     * @throws LogicException 若校验失败，则抛出通用异常
     */
    @Override
    public void checkCreateTrading(Trading tradingEntity) {
        // 1.校验不为为空，订单备注、订单号、商户号、交易金额、支付渠道
        boolean flag = ObjectUtil.isAllNotEmpty(tradingEntity,
                tradingEntity.getMemo(),
                tradingEntity.getProductOrderNo(),
                tradingEntity.getEnterpriseId(),
                tradingEntity.getTradingAmount(),
                tradingEntity.getTradingChannel());
        // 2.金额不能小于等于0
        boolean flag2 = !NumberUtil.isLessOrEqual(tradingEntity.getTradingAmount(), BigDecimal.valueOf(0));
        if (!flag || !flag2) {
            throw new LogicException( TradingEnum.CONFIG_ERROR.getValue());//支付配置错误
        }

        // 3.查询是否有重复的订单号：根据业务标识和订单id查询
        List<Trading> tradings = tradingService.queryByProductOrder(tradingEntity.getProductAppId(), tradingEntity.getProductOrderNo());
        if (ObjectUtil.isEmpty(tradings)) {
            // 3.1没有重复的订单号，就新建交易单，生成交易号
            tradingEntity.setTradingOrderNo((Long) identifierGenerator.nextId(tradingEntity));
            return;
        }
        // 4.存在重复的订单号，找到已付款的记录
        Trading finishedTrading = tradingService.findFinishedTrading(tradingEntity.getProductAppId(), tradingEntity.getProductOrderNo());
        if (ObjectUtil.isNotEmpty(finishedTrading)) {
            // 4.1存在已付款单子直接抛出重复支付异常
            throw new LogicException( TradingEnum.TRADING_STATE_SUCCEED.getValue());//交易单已完成
        }
        // 5.存在重复的订单号，找到该支付渠道支付中的单子
        Trading trading = tradingService.queryDuringTrading(tradingEntity.getProductAppId(), tradingEntity.getProductOrderNo(), tradingEntity.getTradingChannel());
        if (ObjectUtil.isNotEmpty(trading)) {
            // 5.1存在相同支付渠道的付款中单子
            throw new LogicException( TradingEnum.TRADING_STATE_PAYING.getValue());//交易单交易中
        }
        // 6.到了这里，证明重复的订单号都没有交易成功，就新建交易单，生成交易号
        tradingEntity.setTradingOrderNo((Long) identifierGenerator.nextId(tradingEntity));
    }

    /**
     * 校验查询交易单的参数：判断交易单是否存在
     * @param trading 交易实体
     * @throws LogicException 若交易单为空，则抛出通用异常
     */
    @Override
    public void checkQueryTrading(Trading trading) {
        // 检查交易实体是否为空，如果为空则抛出异常
        if (ObjectUtil.isEmpty(trading)) {
            throw new LogicException( TradingEnum.NOT_FOUND.getValue());//交易单不存在
        }
    }

    /**
     * 校验退款交易的参数
     * @param trading     交易实体
     * @param refundAmount 退款金额
     * @throws LogicException 若交易单为空或交易状态不允许退款，则抛出通用异常
     */
    @Override
    public void checkRefundTrading(Trading trading, BigDecimal refundAmount) {
        // 检查交易实体是否为空
        if (ObjectUtil.isEmpty(trading)) {
            throw new LogicException( TradingEnum.NOT_FOUND.getValue());//交易单不存在
        }

        // 检查交易状态是否允许退款
        if (trading.getTradingState() != TradingStateEnum.YJS) {
            throw new LogicException( TradingEnum.NATIVE_REFUND_FAIL.getValue());//统一下单退款交易失败
        }

        // 退款总金额不可超实付总金额
        if (NumberUtil.isGreater(refundAmount, trading.getTradingAmount())) {
            throw new LogicException( TradingEnum.BASIC_REFUND_OUT_FAIL.getValue());//退款金额超过订单总金额
        }
    }

    /**
     * 校验查询退款交易的参数
     * @param refundRecord 退款记录
     * @throws LogicException 若退款记录为空或退款已成功，则抛出通用异常
     */
    @Override
    public void checkQueryRefundTrading(RefundRecord refundRecord) {
        // 检查退款记录是否为空，如果为空，则抛出异常表示未找到退款交易
        if (ObjectUtil.isEmpty(refundRecord)) {
            throw new LogicException( TradingEnum.REFUND_NOT_FOUND.getValue());//退款记录不存在
        }

        // 检查退款状态是否为成功，如果是，则抛出异常表示退款交易已经完成
        if (ObjectUtil.equals(refundRecord.getRefundStatus(), RefundStatusEnum.SUCCESS)) {
            throw new LogicException( TradingEnum.REFUND_ALREADY_COMPLETED.getValue());//退款记录已经完成
        }
    }

    /**
     * 校验关闭交易单的参数
     * @param trading 交易实体
     * @throws LogicException 若交易状态不允许关闭，则抛出通用异常
     */
    @Override
    public void checkCloseTrading(Trading trading) {
        // 检查交易状态是否为"等待付款"，只有此状态下才允许关闭交易
        if (ObjectUtil.notEqual(TradingStateEnum.FKZ, trading.getTradingState())) {
            // 如果交易状态不符合，抛出异常提示关闭失败
            throw new LogicException( TradingEnum.CLOSE_FAIL.getValue());//关闭交易单失败
        }
    }
}

